package com.zsw.exception;

import com.alibaba.fastjson.JSON;
import feign.FeignException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.nio.ByteBuffer;
import java.util.List;
import java.util.Optional;

/**
 * 统一的全局异常处理
 * @author zhangsw
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {FeignException.class})
    public ResponseBaseDTO feignException(FeignException e) {
        //由于上游服务也同样使用了统一数据处理，不管正常还是异常，响应
        //的都是ResponseBaseDTO 。所以这里的responseBody()其实就是
        // ResponseBaseDTO 的json 字符串 。
        Optional<ByteBuffer> byteBuffer = e.responseBody();
        if (byteBuffer.isPresent()) {
            String responseJson = byteBuffer.get().toString();
            ResponseBaseDTO responseBaseDTO = JSON.parseObject(responseJson, ResponseBaseDTO.class);
            return ResponseDTO.error(responseBaseDTO.getCode(), responseBaseDTO.getMessage());
        }
        return ResponseDTO.error(UserErrorEnum.SYS_ERROR, "调用下游服务异常");
    }

    /**
     * 处理系统自定义的业务异常
     * @param ex
     * @return
     */
    @ExceptionHandler(value = {BusinessException.class})
    public ResponseBaseDTO sysExceptionHandler(BusinessException ex){
        return ResponseDTO.error(ex.getCode(),ex.getMsg());
    }

    /**
     * 参数校验异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {BindException.class})
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseBaseDTO validException(BindException e) {
        return this.getValidExceptionResult(e.getBindingResult().getAllErrors());
    }

    /**
     * 运行异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {Exception.class})
    public ResponseBaseDTO exception(Exception e) {
        return ResponseDTO.error(UserErrorEnum.SYS_ERROR);
    }


    /**
     * 参数校验异常处理
     * @param objectErrors
     * @return
     */
    private ResponseBaseDTO getValidExceptionResult(List<ObjectError> objectErrors) {
        StringBuilder sb = new StringBuilder();
        for (ObjectError error : objectErrors) {
            sb.append(error.getObjectName()).append(";");
        }
        String message = sb.length() > 0 ? sb.toString().substring(0, sb.length() - 1) : sb.toString();
        //参数校验失败
        return ResponseDTO.error(UserErrorEnum.VALID_ERROR, message);
    }
}
